/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.utils;

import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.NoneScoped;

@ManagedBean
@NoneScoped
public class SSHManager {

    private static final int COMMAND_EXECUTION_SUCCESS_OPCODE = -2;
    private static String ENTER_CHARACTER = "\r";
    private static final int SSH_PORT = 22;
    private List<String> lstCmds = new ArrayList<String>();
    private static String[] linuxPromptRegEx = new String[]{"\\>", "#", "~#"};
    private Expect4j expect = null;
    private Session session = null;
    private StringBuilder buffer = new StringBuilder();
    private String userName;
    private String password;
    private String host;
    private static SSHManager instance;
    private ChannelShell channel;

    /**
     *
     * @param host
     * @param userName
     * @param password
     */
    private SSHManager() {
        System.out.println("New manager");
    }

    public static SSHManager getInstance() {
        if (instance == null) {
            instance = new SSHManager();
        }
        return instance;
    }

    /**
     *
     * @param cmdsToExecute
     */
    public String execute(ArrayList<String> lstCommands) {

        this.lstCmds = lstCommands;
        Closure closure = new Closure() {
            public void run(ExpectState expectState) throws Exception {
                if (!expectState.getBuffer().contains("Last login")) {
                    buffer.append(expectState.getBuffer());
                }

            }
        };
        List<Match> lstPattern = new ArrayList<Match>();
        for (String regexElement : linuxPromptRegEx) {
            try {
                Match mat = new RegExpMatch(regexElement, closure);
                lstPattern.add(mat);
            } catch (Exception e) {
                System.out.println("Error en la ejecucion de comando ssh: " + e.getMessage());
            }
        }

        try {
            expect = SSH();
            boolean isSuccess = true;
            for (String strCmd : lstCmds) {
                if (!strCmd.equals("")) {
                    isSuccess = isSuccess(lstPattern, strCmd);
                    if (!isSuccess) {
                        isSuccess = isSuccess(lstPattern, strCmd);
                    }
                }
            }

            checkResult(expect.expect(lstPattern));
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Error en la ejecucion");
        } finally {
            closeConnection();
        }
        return buffer.toString();

    }

    /**
     *
     * @param objPattern
     * @param strCommandPattern
     * @return
     */
    private boolean isSuccess(List<Match> objPattern, String strCommandPattern) {
        try {
            boolean isFailed = checkResult(expect.expect(objPattern));

            if (!isFailed) {
                expect.send(strCommandPattern);
                expect.send(ENTER_CHARACTER);
                return true;
            }
            return false;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /**
     *
     * @param hostname
     * @param username
     * @param password
     * @param port
     * @return
     * @throws Exception
     */
    private Expect4j SSH() throws Exception {
        JSch jsch = new JSch();
        session = jsch.getSession(userName, host, SSH_PORT);
        if (password != null) {
            session.setPassword(password);
        }
        Hashtable<String, String> config = new Hashtable<String, String>();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect(300);
        channel = (ChannelShell) session.openChannel("shell");
        Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
        channel.connect();
        return expect;
    }

    /**
     *
     * @param intRetVal
     * @return
     */
    private boolean checkResult(int intRetVal) {
        if (intRetVal == COMMAND_EXECUTION_SUCCESS_OPCODE) {
            return true;
        }
        return false;
    }

    /**
     *
     */
    private void closeConnection() {
        if (expect != null) {
            expect.close();
        }
        //channel.disconnect();
        session.disconnect();
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setHost(String host) {
        this.host = host;
    }
}
